document.addEventListener('DOMContentLoaded', () => {
  //注释有codegeex产生
  // 获取画布容器
  const dropContainer = document.getElementById('dropContainer')
  // 获取工具按钮
  const toolButtons = {},
    panels = {}
  ;['addElementBtn', 'singleArrowBtn', 'doubleArrowBtn', 'exportBtn', 'clearCanvasBtn'].forEach(
    id => (toolButtons[id] = document.getElementById(id))
  )
  ;['libraryPanel', 'customShapePanel', 'exportPanel', 'propertiesMenu', 'overlay'].forEach(
    id => (panels[id] = document.getElementById(id))
  )

  let elements = [],
    arrows = [],
    elementCounter = 0
  let storage = window.localStorage
  let selectedElement = null
  let arrowType = 'single'
  let actionState = {type: null, target: null, startX: 0, startY: 0, hasMoved: false}

  // 初始化函数
  const init = () => {
    setupEventListeners()
    // 获取用户偏好存储类型
    const preferredStorageType = localStorage.getItem('preferredStorageType') || 'localStorage'
    // 设置存储类型
    document.querySelector(
      `input[name="storageType"][value="${preferredStorageType}"]`
    ).checked = true
    storage = window[preferredStorageType]
    // 加载状态
    loadState()
  }

  // 设置事件监听器
  const setupEventListeners = () => {
    // 添加元素按钮
    toolButtons.addElementBtn.addEventListener('click', () => {
      resetModes()
      loadShapesToLibrary()
      showPanel('libraryPanel')
    })
    // 单箭头按钮
    toolButtons.singleArrowBtn.addEventListener('click', () => {
      resetModes(true)
      arrowType = 'single'
      toolButtons.singleArrowBtn.classList.add('active')
      dropContainer.classList.add('drawing-arrow')
    })
    // 双箭头按钮
    toolButtons.doubleArrowBtn.addEventListener('click', () => {
      resetModes(true)
      arrowType = 'double'
      toolButtons.doubleArrowBtn.classList.add('active')
      dropContainer.classList.add('drawing-arrow')
    })
    // 导出按钮
    toolButtons.exportBtn.addEventListener('click', () => {
      resetModes()
      showPanel('exportPanel')
    })
    // 清空画布按钮
    toolButtons.clearCanvasBtn.addEventListener('click', () => {
      if (confirm('您确定要清空整个画布吗？此操作不可撤销。')) clearCanvas()
    })

    // 关闭面板按钮
    document
      .querySelectorAll('.close-btn')
      .forEach(btn => btn.addEventListener('click', closePanels))
    // 遮罩层
    panels.overlay.addEventListener('click', closePanels)
    // 创建自定义形状链接按钮
    document
      .getElementById('createCustomShapeLinkBtn')
      .addEventListener('click', () => showPanel('customShapePanel'))
    // 保存并创建自定义形状按钮
    document
      .getElementById('saveAndCreateCustomShapeBtn')
      .addEventListener('click', saveCustomShape)
    // 应用属性按钮
    document.getElementById('applyPropsBtn').addEventListener('click', applyProperties)
    // 存储类型单选按钮
    document
      .querySelectorAll('input[name="storageType"]')
      .forEach(radio => radio.addEventListener('change', e => setStorageType(e.target.value)))
    // 导入JSON按钮
    document.getElementById('importJsonBtn').addEventListener('click', importJson)
    // 导出JSON按钮
    document.getElementById('exportJsonBtn').addEventListener('click', exportJson)
    // 导出图片按钮
    document.getElementById('exportImageBtn').addEventListener('click', exportImage)

    // 画布鼠标按下事件
    dropContainer.addEventListener('mousedown', onCanvasMouseDown)
    // 鼠标移动事件
    document.addEventListener('mousemove', handleActionMove)
    // 鼠标松开事件
    document.addEventListener('mouseup', handleActionUp)
  }

  // 显示面板
  const showPanel = panelId => {
    closePanels()
    panels.overlay.style.display = 'block'
    panels[panelId].style.display = 'block'
  }
  // 关闭面板
  const closePanels = () => {
    Object.values(panels).forEach(p => (p.style.display = 'none'))
  }
  // 重置模式
  const resetModes = (keepArrowMode = false) => {
    if (!keepArrowMode) {
      dropContainer.classList.remove('drawing-arrow')
      toolButtons.singleArrowBtn.classList.remove('active')
      toolButtons.doubleArrowBtn.classList.remove('active')
    }
    deselectAllElements()
  }

  // 画布鼠标按下事件
  const onCanvasMouseDown = e => {
    if (e.target === dropContainer) deselectAllElements()
    else if (dropContainer.classList.contains('drawing-arrow') && e.target.closest('.element'))
      onArrowStart(e)
  }

  // 元素鼠标按下事件
  const handleMouseDown = e => {
    const targetEl = e.target.closest('.element')
    if (dropContainer.classList.contains('drawing-arrow') || !targetEl) return
    e.stopPropagation()
    const elData = findElement(targetEl.id)
    if (!elData) return
    Object.assign(actionState, {
      target: targetEl,
      startX: e.clientX,
      startY: e.clientY,
      elStartLeft: elData.left,
      elStartTop: elData.top,
      hasMoved: false,
    })
    if (e.target.classList.contains('resize-handle')) {
      actionState.type = 'resize'
      actionState.handle = e.target.className.split(' ')[1]
      actionState.startRect = targetEl.getBoundingClientRect()
    } else if (!e.target.isContentEditable) {
      actionState.type = 'drag'
    }
  }

  // 动作移动事件
  const handleActionMove = e => {
    if (!actionState.type) return
    if (
      !actionState.hasMoved &&
      (Math.abs(e.clientX - actionState.startX) > 4 || Math.abs(e.clientY - actionState.startY) > 4)
    ) {
      actionState.hasMoved = true
      if (actionState.type === 'drag') {
        selectElement(actionState.target)
        actionState.target.classList.add('dragging')
      }
    }
    if (actionState.hasMoved) {
      const dx = e.clientX - actionState.startX
      const dy = e.clientY - actionState.startY
      if (actionState.type === 'drag') {
        actionState.target.style.left = `${actionState.elStartLeft + dx}px`
        actionState.target.style.top = `${actionState.elStartTop + dy}px`
      } else if (actionState.type === 'resize') {
        let newWidth = actionState.startRect.width,
          newHeight = actionState.startRect.height,
          newLeft = actionState.elStartLeft,
          newTop = actionState.elStartTop
        if (actionState.handle.includes('r')) newWidth = actionState.startRect.width + dx
        if (actionState.handle.includes('l')) {
          newWidth = actionState.startRect.width - dx
          newLeft = actionState.elStartLeft + dx
        }
        if (actionState.handle.includes('b')) newHeight = actionState.startRect.height + dy
        if (actionState.handle.includes('t')) {
          newHeight = actionState.startRect.height - dy
          newTop = actionState.elStartTop + dy
        }
        if (actionState.target.classList.contains('circle')) {
          const newSize = Math.max(newWidth, newHeight)
          newWidth = newSize
          newHeight = newSize
        }
        actionState.target.style.width = `${Math.max(50, newWidth)}px`
        actionState.target.style.height = `${Math.max(50, newHeight)}px`
        actionState.target.style.left = `${newLeft}px`
        actionState.target.style.top = `${newTop}px`
      }
      updateConnectedArrows(actionState.target.id)
    }
  }

  // 动作松开事件
  const handleActionUp = e => {
    if (!actionState.type) return
    const el = actionState.target
    const elData = findElement(el.id)
    if (actionState.hasMoved) {
      el.classList.remove('dragging')
      if (elData) {
        Object.assign(elData, {
          left: el.offsetLeft,
          top: el.offsetTop,
          width: el.offsetWidth,
          height: el.offsetHeight,
        })
        saveState()
      }
    } else if (actionState.type === 'drag') {
      selectElement(el)
    }
    actionState = {type: null, target: null, startX: 0, startY: 0, hasMoved: false}
  }

  // 创建元素
  const createElement = options => {
    const defaults = {left: 150, top: 150, width: 180, height: 80, content: '可编辑内容'}
    if (options.type === 'label') Object.assign(defaults, {width: 120, height: 40, content: '标签'})
    if (options.shape === 'circle') {
      const size = Math.min(defaults.width, defaults.height)
      defaults.width = size
      defaults.height = size
    }
    const config = {
      ...defaults,
      id: `el-${elementCounter++}`,
      shape: 'rectangle',
      styles: {
        backgroundColor: '#ffffff',
        borderColor: '#000000',
        color: '#2c3e50',
        fontSize: '14px',
      },
      ...options,
    }
    const el = document.createElement('div')
    el.id = config.id
    el.className = `element ${config.type} ${config.shape}`
    Object.assign(el.style, {
      left: `${config.left}px`,
      top: `${config.top}px`,
      width: `${config.width}px`,
      height: `${config.height}px`,
    })
    el.innerHTML = `<div class="element-shape"></div><div class="element-content">${config.content}</div>`
    dropContainer.appendChild(el)
    applyStyles(el, config.styles)
    initElement(el)
    elements.push({domElement: el, ...config})
    saveState()
    selectElement(el)
  }
  // 初始化元素
  const initElement = el => {
    el.addEventListener('mousedown', handleMouseDown)
    el.addEventListener('contextmenu', onElementContextMenu)
    const contentEl = el.querySelector('.element-content')
    contentEl.addEventListener('dblclick', function (e) {
      e.stopPropagation()
      this.setAttribute('contenteditable', 'true')
      this.focus()
      document.execCommand('selectAll', false, null)
    })
    contentEl.addEventListener('blur', function () {
      this.setAttribute('contenteditable', 'false')
      const elData = findElement(el.id)
      if (elData) {
        elData.content = this.innerHTML
        saveState()
      }
    })
    contentEl.addEventListener('keydown', e => {
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault()
        e.target.blur()
      }
    })
  }
  // 选择元素
  const selectElement = el => {
    if (selectedElement && selectedElement.domElement === el) return
    deselectAllElements()
    selectedElement = findElement(el.id)
    if (!selectedElement) return
    el.classList.add('selected')
    createControls(el)
  }
  // 取消选择所有元素
  const deselectAllElements = () => {
    if (selectedElement) {
      selectedElement.domElement.classList.remove('selected')
      selectedElement.domElement
        .querySelectorAll('.resize-handle, .remove-element-btn')
        .forEach(ctrl => ctrl.remove())
    }
    selectedElement = null
  }
  // 创建控件
  const createControls = el => {
    ;['tl', 'tr', 'bl', 'br'].forEach(pos => {
      const h = document.createElement('div')
      h.className = `resize-handle ${pos}`
      el.appendChild(h)
    })
    const btn = document.createElement('button')
    btn.className = 'remove-element-btn'
    btn.innerHTML = '×'
    btn.addEventListener('mousedown', e => {
      e.stopPropagation()
      if (confirm(`确定要删除 "${selectedElement.name}" 吗?`)) {
        removeElement(el.id)
      }
    })
    el.appendChild(btn)
  }
  // 移除元素
  const removeElement = elementId => {
    const elData = findElement(elementId)
    if (!elData) return
    arrows = arrows.filter(arrow => {
      if (arrow.startElId === elementId || arrow.endElId === elementId) {
        arrow.line?.remove()
        arrow.head?.remove()
        arrow.head2?.remove()
        return false
      }
      return true
    })
    elData.domElement.remove()
    elements = elements.filter(el => el.id !== elementId)
    selectedElement = null
    saveState()
  }
  // 查找元素
  const findElement = id => elements.find(el => el.id === id)

  // 应用样式
  const applyStyles = (domEl, styles) => {
    const shapeEl = domEl.querySelector('.element-shape')
    const contentEl = domEl.querySelector('.element-content')
    if (shapeEl) {
      shapeEl.style.backgroundColor = styles.borderColor
    }
    if (contentEl) {
      contentEl.style.backgroundColor = styles.backgroundColor
      contentEl.style.color = styles.color
      contentEl.style.fontSize = styles.fontSize
    }
  }

  // 元素右键菜单事件
  const onElementContextMenu = e => {
    e.preventDefault()
    selectElement(e.currentTarget)
    if (!selectedElement) return
    const s = selectedElement.styles
    document.getElementById('propBgColor').value = s.backgroundColor
    document.getElementById('propBorderColor').value = s.borderColor
    document.getElementById('propFontColor').value = s.color
    document.getElementById('propFontSize').value = parseInt(s.fontSize)
    panels.propertiesMenu.style.left = `${e.clientX + 5}px`
    panels.propertiesMenu.style.top = `${e.clientY + 5}px`
    showPanel('propertiesMenu')
  }
  // 应用属性
  const applyProperties = () => {
    if (!selectedElement) return
    const s = selectedElement.styles
    s.backgroundColor = document.getElementById('propBgColor').value
    s.borderColor = document.getElementById('propBorderColor').value
    s.color = document.getElementById('propFontColor').value
    s.fontSize = `${document.getElementById('propFontSize').value}px`
    applyStyles(selectedElement.domElement, s)
    saveState()
    closePanels()
  }

  // 加载形状到库
  const loadShapesToLibrary = () => {
    const container = document.getElementById('libraryContent')
    container.innerHTML = ''
    const sections = {
      基础盒子: [
        {name: '矩形盒子', type: 'box', shape: 'rectangle'},
        {name: '圆形盒子', type: 'box', shape: 'circle'},
        {name: '三角形盒子', type: 'box', shape: 'triangle'},
      ],
      基础标签: [
        {name: '矩形标签', type: 'label', shape: 'rectangle'},
        {name: '圆形标签', type: 'label', shape: 'circle'},
        {name: '三角标签', type: 'label', shape: 'triangle'},
      ],
      自定义盒子: JSON.parse(localStorage.getItem('customShapes')) || [],
    }
    for (const [title, shapes] of Object.entries(sections)) {
      if (shapes.length === 0) continue
      const sectionEl = document.createElement('div')
      sectionEl.className = 'library-section'
      let gridHTML = ''
      shapes.forEach(shapeData => {
        gridHTML += `<div class="library-item ${shapeData.shape}" data-type="${shapeData.type}"><div class="library-preview"><div class="library-preview-shape"></div><div class="library-preview-content"></div></div><div class="item-name">${shapeData.name}</div></div>`
      })
      sectionEl.innerHTML = `<h3>${title}</h3><div class="library-grid">${gridHTML}</div>`
      container.appendChild(sectionEl)
    }
    container.querySelectorAll('.library-item').forEach(item => {
      const type = item.dataset.type
      const shape = [...item.classList].find(c => c !== 'library-item')
      const name = item.querySelector('.item-name').textContent
      const customShapeData = sections['自定义盒子'].find(s => s.name === name)
      item.addEventListener('click', () => {
        createElement(customShapeData || {name, type, shape})
        closePanels()
      })
    })
  }
  // 保存自定义形状
  const saveCustomShape = () => {
    const name = document.getElementById('customShapeName').value.trim()
    const pointsStr = document.getElementById('customShapePoints').value.trim()
    if (!name || !pointsStr) return alert('请填写形状名称和坐标点。')
    const shapeData = {name: name, type: 'box', shape: 'custom', points: pointsStr}
    let customShapes = JSON.parse(localStorage.getItem('customShapes')) || []
    customShapes.push(shapeData)
    localStorage.setItem('customShapes', JSON.stringify(customShapes))
    createElement(shapeData)
    closePanels()
  }

  // 箭头开始事件
  const onArrowStart = e => {
    const startEl = e.target.closest('.element')
    if (!startEl) return
    resetModes(true)
    let tempLine = document.createElement('div')
    tempLine.className = 'arrow-line'
    dropContainer.appendChild(tempLine)
    let tempHead = document.createElement('div')
    tempHead.className = `arrow-head ${arrowType}`
    dropContainer.appendChild(tempHead)
    let tempHead2 = null
    if (arrowType === 'double') {
      tempHead2 = document.createElement('div')
      tempHead2.className = 'arrow-head single'
      dropContainer.appendChild(tempHead2)
    }
    const onArrowMove = moveEvent => {
      const mouseX = moveEvent.clientX - dropContainer.getBoundingClientRect().left
      const mouseY = moveEvent.clientY - dropContainer.getBoundingClientRect().top
      const startEdge = getEdgePoint(startEl, {x: mouseX, y: mouseY})
      updateArrowDOM(
        tempLine,
        tempHead,
        tempHead2,
        startEdge.x,
        startEdge.y,
        mouseX,
        mouseY,
        arrowType
      )
    }
    const onArrowUp = upEvent => {
      tempLine.remove()
      tempHead.remove()
      if (tempHead2) tempHead2.remove()
      const endElement = upEvent.target.closest('.element')
      if (endElement && startEl.id !== endElement.id) {
        createArrow(startEl.id, endElement.id, arrowType)
      }
      document.removeEventListener('mousemove', onArrowMove)
      resetModes()
    }
    document.addEventListener('mousemove', onArrowMove)
    document.addEventListener('mouseup', onArrowUp, {once: true})
  }
  const createArrow = (startElId, endElId, type) => {
    const arrow = {
      id: `arrow-${Date.now()}`,
      startElId,
      endElId,
      type,
      line: document.createElement('div'),
      head: document.createElement('div'),
      head2: null,
    }
    arrow.line.className = 'arrow-line'
    arrow.head.className = `arrow-head ${type === 'double' ? 'double' : 'single'}`
    if (type === 'double') {
      arrow.head2 = document.createElement('div')
      arrow.head2.className = 'arrow-head single'
      dropContainer.appendChild(arrow.head2)
    }
    dropContainer.appendChild(arrow.line)
    dropContainer.appendChild(arrow.head)
    arrows.push(arrow)
    updateConnectedArrows(startElId)
    saveState()
  }
  const updateConnectedArrows = elementId => {
    arrows.forEach(arrow => {
      if (arrow.startElId === elementId || arrow.endElId === elementId) {
        const startEl = document.getElementById(arrow.startElId)
        const endEl = document.getElementById(arrow.endElId)
        if (!startEl || !endEl) return
        const endCenter = {
          x: endEl.offsetLeft + endEl.offsetWidth / 2,
          y: endEl.offsetTop + endEl.offsetHeight / 2,
        }
        const startCenter = {
          x: startEl.offsetLeft + startEl.offsetWidth / 2,
          y: startEl.offsetTop + startEl.offsetHeight / 2,
        }
        const startEdge = getEdgePoint(startEl, endCenter)
        const endEdge = getEdgePoint(endEl, startCenter)
        updateArrowDOM(
          arrow.line,
          arrow.head,
          arrow.head2,
          startEdge.x,
          startEdge.y,
          endEdge.x,
          endEdge.y,
          arrow.type
        )
      }
    })
  }
  const getEdgePoint = (el, targetPoint) => {
    const w = el.offsetWidth,
      h = el.offsetHeight
    const cx = el.offsetLeft + w / 2,
      cy = el.offsetTop + h / 2
    if (el.classList.contains('circle')) {
      const angle = Math.atan2(targetPoint.y - cy, targetPoint.x - cx)
      return {x: cx + (w / 2) * Math.cos(angle), y: cy + (h / 2) * Math.sin(angle)}
    }
    const dx = targetPoint.x - cx,
      dy = targetPoint.y - cy,
      tan_p = h / w,
      tan_m = Math.abs(dy / dx)
    let x, y
    if (tan_m < tan_p) {
      x = cx + (Math.sign(dx) * w) / 2
      y = cy + ((Math.sign(dx) * w) / 2) * tan_m
    } else {
      x = cx + (Math.sign(dy) * h) / 2 / tan_m
      y = cy + (Math.sign(dy) * h) / 2
    }
    return {x, y}
  }
  const updateArrowDOM = (line, head, head2, x1, y1, x2, y2, type) => {
    const dx = x2 - x1,
      dy = y2 - y1
    const length = Math.sqrt(dx * dx + dy * dy)
    const angleRad = Math.atan2(dy, dx)
    line.style.left = `${x1}px`
    line.style.top = `${y1}px`
    line.style.width = `${length}px`
    line.style.transform = `rotate(${angleRad}rad)`
    head.style.transform = `translate(-50%, -50%) rotate(${angleRad}rad)`
    head.style.left = `${x2}px`
    head.style.top = `${y2}px`
    if (type === 'double' && head2) {
      head2.style.transform = `translate(-50%, -50%) rotate(${angleRad + Math.PI}rad)`
      head2.style.left = `${x1}px`
      head2.style.top = `${y1}px`
    }
  }

  const clearCanvas = () => {
    elements = []
    arrows = []
    elementCounter = 0
    dropContainer.innerHTML = ''
    saveState()
  }
  const setStorageType = type => {
    saveState()
    storage = window[type]
    localStorage.setItem('preferredStorageType', type)
    loadState()
  }
  const saveState = () => {
    if (!storage) return
    const state = {
      elements: elements.map(el => ({
        id: el.id,
        type: el.type,
        shape: el.shape,
        name: el.name,
        left: el.left,
        top: el.top,
        width: el.width,
        height: el.height,
        content: el.content,
        styles: el.styles,
        points: el.points,
      })),
      arrows: arrows.map(a => ({startElId: a.startElId, endElId: a.endElId, type: a.type})),
      elementCounter,
    }
    storage.setItem('diagramState', JSON.stringify(state))
  }
  const loadState = () => {
    const stateJSON = storage.getItem('diagramState')
    if (!stateJSON || JSON.parse(stateJSON).elements.length === 0) {
      clearCanvas()
      return
    }
    try {
      const state = JSON.parse(stateJSON)
      clearCanvas()
      elementCounter = state.elementCounter || 0
      if (state.elements) state.elements.forEach(elData => createElement(elData))
      if (state.arrows)
        state.arrows.forEach(arrowData =>
          createArrow(arrowData.startElId, arrowData.endElId, arrowData.type)
        )
      deselectAllElements()
    } catch (e) {
      console.error('加载状态失败:', e)
      storage.removeItem('diagramState')
    }
  }
  const importJson = () => {
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = '.json'
    input.onchange = e => {
      const file = e.target.files[0]
      if (!file) return
      const reader = new FileReader()
      reader.onload = event => {
        storage.setItem('diagramState', event.target.result)
        loadState()
      }
      reader.readAsText(file)
    }
    input.click()
    closePanels()
  }
  const exportJson = () => {
    saveState()
    const dataStr = storage.getItem('diagramState')
    if (!dataStr || JSON.parse(dataStr).elements.length === 0) return alert('没有可导出的数据。')
    const blob = new Blob([dataStr], {type: 'application/json'})
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = 'diagram.json'
    a.click()
    URL.revokeObjectURL(url)
    closePanels()
  }
  const exportImage = () => {
    deselectAllElements()
    setTimeout(() => {
      html2canvas(dropContainer, {
        backgroundColor: '#ffffff',
        logging: false,
        useCORS: true,
      }).then(canvas => {
        const a = document.createElement('a')
        a.href = canvas.toDataURL('image/png')
        a.download = 'diagram.png'
        a.click()
      })
    }, 100)
    closePanels()
  }

  init()
})
